﻿using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Playables;
#if SHADER_ANIMATED
using FSG.MeshAnimator.ShaderAnimated;
#endif

namespace GameDesigner
{
    /// <summary>
    /// 状态机 v2017/12/6
    /// </summary>
    public class StateMachineMono : StateMachineView
    {
        /// <summary>
        /// 动画选择模式
        /// </summary>
        public AnimationMode animMode;

        /// <summary>
        /// 旧版动画组件
        /// </summary>
        public new Animation animation;

        /// <summary>
        /// 新版动画组件
        /// </summary>
        public Animator animator;

        /// <summary>
        /// 可播放导演动画
        /// </summary>
        public PlayableDirector director;
#if SHADER_ANIMATED
        /// <summary>
        /// shader动画组件
        /// </summary>
        public ShaderMeshAnimator meshAnimator;
#endif

        // 旧版本兼容问题，如果去掉这个字段，之前的状态会全部丢失！
#if UNITY_2020_1_OR_NEWER
        [NonReorderable]
#endif
        public State[] states;

        public override Transform Parent => transform.parent != null ? transform.parent : transform;

        public static StateMachineMono CreateSupport(string name = "Base Layer")
        {
            var monoStateMachine = new GameObject(name).AddComponent<StateMachineMono>();
            monoStateMachine.name = name;
            var controller = new StateController
            {
                View = monoStateMachine,
                layers = new StateLayer[0]
            };
            var layer = controller.AddNewLayer(name);
            layer.Weight = 1f;
            monoStateMachine.controller = controller;
#if UNITY_EDITOR
            monoStateMachine.editStateMachine = layer.stateMachine;
#endif
            return monoStateMachine;
        }

        public override void Init(params object[] args)
        {
            switch (animMode)
            {
                case AnimationMode.Animation:
                    controller.Init(this, (layer) => new AnimationStateMachine(animation, layer), args);
                    break;
                case AnimationMode.Animator:
                    controller.Init(this, (layer) => new AnimatorStateMachine(animator, layer), args);
                    break;
                case AnimationMode.Timeline:
                    controller.Init(this, (layer) => new TimelineStateMachine(animator, director, layer), args);
                    break;
                case AnimationMode.Time:
                    controller.Init(this, (layer) => new TimeStateMachine(), args);
                    break;
#if SHADER_ANIMATED
                case AnimationMode.MeshAnimator:
                    controller.Init(this, (layer) => new MeshAnimatorStateMachine(meshAnimator), args);
                    break;
#endif
            }
        }

#if UNITY_EDITOR
        public override void GetClipNames(Transform root, List<string> clipNames)
        {
            if (animation == null)
                animation = GetComponentInChildren<Animation>();
            if (animation != null)
            {
                var clips = UnityEditor.AnimationUtility.GetAnimationClips(animation.gameObject);
                clipNames.Clear();
                foreach (var clip in clips)
                    clipNames.Add(clip.name);
            }

            if (animator == null)
                animator = root.GetComponentInChildren<Animator>();
            AnimatorStateMachineView.GetClipNames(animator, clipNames);

            if (director == null)
                director = root.GetComponentInChildren<PlayableDirector>();
#if SHADER_ANIMATED
            if (meshAnimator == null)
                meshAnimator = root.GetComponentInChildren<ShaderMeshAnimator>();
            if (meshAnimator != null)
            {
                var clips = meshAnimator.animations;
                clipNames.Clear();
                foreach (var clip in clips)
                    clipNames.Add(clip.AnimationName);
            }
#endif
            if (animClipReference is IAnimationClipReference animationClipReference)
            {
                clipNames.Clear();
                clipNames.AddRange(animationClipReference.ClipNames);
            }
        }

        public override float GetAnimClipLength(StateAction action)
        {
            switch (animMode)
            {
                case AnimationMode.Animation:
                    {
                        var clip = animation.GetClip(action.clipName);
                        if (clip == null)
                            return 0f;
                        return clip.length;
                    }
                case AnimationMode.Animator:
                    return AnimatorStateMachineView.GetAnimClipLength(animator, action);
                case AnimationMode.Timeline:
                    if (action.clipAsset != null)
                        return (float)(action.clipAsset as PlayableAsset).duration;
                    return AnimatorStateMachineView.GetAnimClipLength(animator, action);
                case AnimationMode.Time:
                    break;
                case AnimationMode.None:
                    break;
            }
            return 0f;
        }
#endif
    }
}